package gov.mogaha.ntis.cmm.mob.servlet;

import gov.mogaha.ntis.cmm.mob.servlet.bean.UserInfo;

import java.util.ArrayList;
import java.util.Hashtable;

import wire.client.HttpConnector;
import wire.proto.Binding;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;

public class CmmMobServlet extends Thread {
	
 
	//생성,조회 구분
	public static final int SERVLET_CU = 3;
	public static final int SERVLET_RD = 4;
	
	//public static final String FILEPATH = "/sdcard";

//	public static final String FILENAME = "test.dat";
	
	//서버 ip,port
	public final static String SERVER_IP = "10.46.107.236";
	public final static int SERVER_PORT = 8206;
	//public final static String SERVER_IP = "210.220.217.132";
	//public final static int SERVER_PORT = 18206;
	
	SharedPreferences preference;
	//private SharedPreferences.Editor prefEdit;
	
	WireClient 	client;
	private Binding result;
	
	String mWidl, mTag;
	
	Handler 	mHandler;
	Context 	mContext;
	String 		mSvc;
	Binding 	mBinding;
	UserInfo 	mUserInfo;
	boolean 	insert;
	
	public CmmMobServlet(Context context, String widl, String tag, String svc, Handler handler, Binding binding) {
		// TODO Auto-generated constructor stub
		this.mWidl = widl;
		this.mTag = tag;
		this.mContext = context;
		this.mHandler = handler;
		this.mSvc = svc;
		this.mBinding = binding;
	}
	
	public CmmMobServlet(Context context, String widl, String tag, String svc, Handler handler, Binding binding, boolean isInsert) {
		// TODO Auto-generated constructor stub
		insert = isInsert;
		this.mWidl = widl;
		this.mTag = tag;
		this.mContext = context;
		this.mHandler = handler;
		this.mSvc = svc;
		this.mBinding = binding;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		super.run();
//		mUserInfo = new UserInfo();
		mHandler.sendEmptyMessage(CmmMobServletHandler.CONN_START);
		try {
			result = servletConnect();
		} catch (Exception e) {
			mHandler.sendEmptyMessage(HttpConnector.CONNECT_ERROR);
		}finally{
			DataSet data = new DataSet();
			data.setBindData(result);
			Message msg = Message.obtain();
			msg.what = CmmMobServletHandler.CONN_END;
			msg.obj = data;
			mHandler.sendMessage(msg);
		}
		
	}
	int retryCnt = 0;
	private Binding servletConnect() {
		// TODO Auto-generated method stub
		//WireClient 인스턴스 생성 및 서버연결
		client = WireClient.getInstance();
		
		//테스트용
		//if (client.setConfig(mTag)) {
		//	client.connectWireServer(SERVER_IP, SERVER_PORT);
		//}
		Log.d("debug", "mTag:" + mTag);
		if (client.setConfig(mTag)) {
			Log.d("debug", "SID:"+client.getSID());
			client.connectWireServer(SERVER_IP, SERVER_PORT, client.getSID());
			
		}
		//실제적용
//			client.connectWireServer(SERVER_IP, SERVER_PORT, client.getSID());
		//인증서인증 테스트시에만 적용
//		if (mUserInfo == null) {
//			try {
//				cert();
//			} catch (NotCertificateException e) {
//				// TODO Auto-generated catch block
//				mHandler.sendEmptyMessage(CmmMobServletHandler.CERT_ERROR);
//			}
//		}
		//파라미터
		if (mBinding == null) {
			mBinding = new Binding();
		}
		// 1. 서블릿에서 정의한 값들을  Binding 객체에 넣어줍니다.
//		mBinding.putEnc("userid", mUserInfo.getUserId());
//		mBinding.putEnc("officecode", mUserInfo.getOfficecode());
//		mBinding.putEnc("cgg_code", mUserInfo.getGcc_code());
//		mBinding.putEnc("sso_org_id", mUserInfo.getSso_org_id());			
		
		// 2. getOutputs Method 를 이용하여 검색 결과를 얻습니다.
		try {
			result = client.getOutputs(mWidl, mSvc, mBinding);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			Log.d("debug", "CommMobServlet Error : " +e.getMessage());
				switch (client.getLastError()) {
				case HttpConnector.CONNECT_ERROR:
					mHandler.sendEmptyMessage(HttpConnector.CONNECT_ERROR);
					break;
				case HttpConnector.SEND_ERROR:
					if (insert) {
						if(retryCnt == 5){
							mHandler.sendEmptyMessage(HttpConnector.SEND_ERROR);
							retryCnt = 0;
							//암호화
							break;
						}
						this.run();
						retryCnt ++;
						break;
					}else {
						mHandler.sendEmptyMessage(HttpConnector.SEND_ERROR);
						break;
					}
				case HttpConnector.RECEIVE_ERROR:
					if (insert) {
						if(retryCnt == 5){
							mHandler.sendEmptyMessage(HttpConnector.RECEIVE_ERROR);
							retryCnt = 0;
							//암호화
							break;
						}
						this.run();
						retryCnt ++;
						break;
					}else {
						mHandler.sendEmptyMessage(HttpConnector.RECEIVE_ERROR);
						break;
					}
				case HttpConnector.ETC_ERROR:
					mHandler.sendEmptyMessage(HttpConnector.ETC_ERROR);
					break;
				default:
					break;
				}
				//암호화
//				cfmDataEnc();
				//초기화
		}
		return result;
	}
	
	/**
	 * 등록을 위해 전달된 Binding 객체의 암호화 확인
	 */
	/*private void cfmDataEnc() {
		preference = PreferenceManager.getDefaultSharedPreferences(mContext);
		prefEdit = preference.edit();
		// TODO Auto-generated method stub
		AlertDialog.Builder alert = new AlertDialog.Builder(mContext);
		alert.setTitle("암호화");
		alert.setMessage("통신중 에러로 인해 전송에 실패했습니다. 입력하신 데이터를 저장하였다가 나중에 다시 전송하시겠습니까?");
		alert.setPositiveButton("예", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				//암호화작업 시작
				dataEnc();
				dialog.dismiss();
			}
		}).setNegativeButton("아니오", new DialogInterface.OnClickListener() {
			
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				dialog.dismiss();
				dialog.cancel();
			}
		}).show();
	}*/
	
	/**
	 * 등록을 위해 전달된 Binding 객체의 암호화 진행
	 */
	/*private void dataEnc() {
		// TODO Auto-generated method stub
		new Runnable() {
			public void run() {
				try {
					String src = mBinding.toString2();
					byte[] binSrc = src.getBytes();
					
					byte[] binData = CertUtil.encData(mContext, binSrc);
					
					if(binData != null && binData.length > 0){
						if(CertUtil.saveFile(binData,FILEPATH,FILENAME)){
							//추후 복호화 및 서버전송을 위한 내용으로 재정의 필요
							prefEdit.putString("filepath", FILEPATH+FILENAME);
							prefEdit.putString("svc", mSvc);
							prefEdit.putString("userid", mUserInfo.getUserId());
							prefEdit.commit();
						}							
					}
				} catch (Exception e) {
					// TODO: handle exception
					e.getMessage();
				}
			}
		}.run();
	}*/
	
	/**
	 * 기존에 서버에 전송하지 못하고 저장되어있는 데이터가 있는지 확인
	 * @param context
	 */
	public void CheckEncDataExist(Context context){
		mContext = context;
		preference = PreferenceManager.getDefaultSharedPreferences(mContext);
//		String filePath = preference.getString("filepath", "");
		//String svc = preference.getString("filepath", "");
		//String userid = preference.getString("userid", "");
		//File file = new File(filePath);
		
		return;
		//작업진행중이며 통신과정 완료 후 작업
//		if (file.exists()) {
//			Dialog dial = new Dialog(context);
//			dial.setContentView(R.layout.dec_chk_dialog_layout);
//			dial.setTitle("인증서 암호를 입력하세요.");
//		}
	}

	/**
	 * 인증
	 */
	/*private void cert() throws NotCertificateException {
//		byte[] binCert = CertUtil.loadCert(mContext);
		//인증은 실제 통합앱을 포함한 테스트에서는 사용하지 않기때문에 임시로 HEX데이터 상태의 인증서를 넣고 byte[]로 변환하여 개발 시 사용 
		byte[] binCert = hexToByteArray(
			    "3082058a30820472a00302010202104de49dfc023693ebb9b3d305d20031d3300d06092a864886f70d01010505003050310b3009060355040613024b52311c301a0603" +
				"55040a1313476f7665726e6d656e74206f66204b6f726561310d300b060355040b130447504b49311430120603550403130b4341313331303030303032301e1" +
				"70d3131303533313037353132345a170d3133303833313037353132345a308185310b3009060355040613024b52311c301a060355040a0c13476f7665726e6d" +
				"656e74206f66204b6f726561312d302b060355040b0c24eca095ebb680eca084ec9e90ebacb8ec849cec9ca0ed86b5eab480eba6acec84bced84b0310f300d0" +
				"60355040b0c0670656f706c653118301606035504030c0f393939ebb095eca095ecb2a0303031308201b83082012d06082a831a8c9a4401153082011f028181" +
				"00940f2886f849956805be4d218f448ab5aa0877beb6a54c783676dcca03aae5f9ff6de10b13c0c30902053910a333d6c07a7a1652ffd3ff7576f8c1943f429" +
				"50b968b889a31cef1184d1d17fde6a54b03c303155d4e3b7eaa4ed8605388c2a94ebd824cb0d0fba7f6c8583daad73e5e07ec4198a7f8499daf04474d590460" +
				"cda3021500f16ef4500e045f30ca486848b02e9a0ebdbcb44b028181008c7c44bbcf8c1cd086c7be59f4aa45e07e53c34303e7bbee8e6006729ef2ff7728e69" +
				"3afb66f00ce7dcdad5f5ba1d4b9d93b03553d2f2cecf34ec084a8f5fc6ef44c3119bec4baff8fa989af3e87034dfd61e4e9ceab6331d628478244795924c257" +
				"81ecf0f8ee5ce8118b8f69a321ccfec99629c067f9ba3225282abcf2e32a038184000281803c9c28ebe2088be88506ff4ac217c61c957a25204092fef4b6f00" +
				"ad5ff10be9319d9f47734eabf94cc97723323418e63ca4eb1a3124021351ecb2189ef4871f5c59c594305332b1c7d70938256dc418adcd485777336adefdc61" +
				"74ac55036770154fd770fdc656f5680243641897ca1e8ad3ba314b2258a043210e04c1c83797a38201923082018e301f0603551d230418301680148dc55e318" +
				"5df928f56e4160d01815828f617a76f301d0603551d0e04160414bbbefd5c453c0e5adb49464d4f5031463f57716c300e0603551d0f0101ff04040302078030" +
				"160603551d20040f300d300b06092a831a868d2102020130610603551d110101ff04573055a05306092a831a8c9a440a0101a04630440c0f393939ebb095eca" +
				"095ecb2a03030313031302f060a2a831a8c9a440a0101013021300706052b0e03021aa01604141b371fe6716f098ac532a05f516779919d429fc23081880603" +
				"551d1f048180307e307ca07aa07886766c6461703a2f2f63656e2e6469722e676f2e6b723a3338392f636e3d63726c313332372c636e3d43413133313030303" +
				"030322c6f753d47504b492c6f3d476f7665726e6d656e74206f66204b6f7265612c633d4b523f63657274696669636174655265766f636174696f6e6c697374" +
				"3b62696e617279303606082b06010505070101042a3028302606082b06010505073001861a687474703a2f2f6776612e67706b692e676f2e6b723a383038303" +
				"00d06092a864886f70d010105050003820101001901d2e57c6a10e841c77d9c9a536ee4abf05e2c6fcc94255aabfa5988ba084745799a30e0782366810695ef" +
				"7a40ccfe7ce2e517aee01ded4f7e90685d948ae1b8ad2c3555c75f843625c84923d4f8b2654b78393540b85a69243f3bb20478b2696bd38eec403950dd5a016" +
				"bbba408db802e2106342f37c7eeb9fb767c61fdaf9a13665d9961f4e3ddde4c55b2d13da7da0b3e17a897b0a2fc4dcfd58982b5287b2b790a6324f45bfee632" +
				"d9c428a47a01b4bc2059686e5bd0bc7b07bf5f7b269011a4cae0180b6871f900359fc46326bd6151328ffffbf372f4f267a06e4bff349337765cb6755d00a08" +
				"490909f50f6be6b73f3b4a3e133d6ce1fc0ded543ae");
		if(binCert != null && binCert.length > 0){
			try {
				client.certAuthentication(binCert, getPhoneNumer());
			} catch (UserNullException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SsoIdException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SsoLoginException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		mUserInfo = client.getUserInfo();
	}*/
	
	
	
	// hex to byte[]
	public static byte[] hexToByteArray(String hex) {
	    if (hex == null || hex.length() == 0) {
	        return null;
	    }

	    byte[] ba = new byte[hex.length() / 2];
	    for (int i = 0; i < ba.length; i++) {
	        ba[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
	    }
	    return ba;
	}
	
	
	
	
	/**
	 * 전화번호 읽어오기
	 * @return
	 */
/*	private String getPhoneNumer(){
		TelephonyManager tm = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
//		return tm.getLine1Number(); 
		return "01012345678"; 	//test
	}*/
	
	/**
	 * Binding 객체에 포함되지 않은 key값을 호출할 경우 NullpointException을 막기위한 클래스
	 * @author itatech
	 *
	 */
	public static class DataSet {
		public static Binding bindData;
		public void setBindData(Binding binding){
			bindData = binding;
		}
		/**
		 * 	입력된 키값이 null일 경우 공백("")으로 리턴하는데 받는값의 속성에 따라 캐스팅하셔서 사용하시면 됩니다.
		 * ex) String[] values = (String[])data.getData("key");
		 * @param key
		 * @return String
		 */
		public String getData(String key) {
			// TODO Auto-generated method stub
			if (bindData != null) {
				return (String)(bindData.get(key)== null?"":bindData.get(key));
			}else {
				return "";
			}
		}
		
		/**
		 * Binding 객체 자체를 리턴
		 * @return
		 */
		public Binding getBinding(){
			return bindData;
		}

		
		/**
		 * Binding 객체 자체를 리턴
		 * @return
		 */
		public Object[] getKeys(){
			return bindData.keySet().toArray();
		}
		
		/**
		 * Binding 객체의 사이즈를 리턴
		 * @return
		 */
		public int getSize(){
			return bindData.size();
		}
		
		/**
		 * 리스트를 데이터만을  Arraylist로 리턴
		 * @return ArrayList<Hashtable<String, String>> 
		 */
		public ArrayList<Hashtable<String, String>> getHashData(){
			ArrayList<Hashtable<String, String>> hashData = new ArrayList<Hashtable<String,String>>();
			Object[] keys =  bindData.keySet().toArray();
			int maxSize = 0;
			//가장 긴 배열 찾기
			if (keys.length > 0) {
				
				for (Object string : keys) {
					try {
						int tmpSize = ((String[])bindData.get(string)).length;
						if (maxSize < tmpSize) {
							maxSize = tmpSize;	//일단 String[]로 캐스팅 되고 maxsize인 데이터를 배열데이터로 판단
						}
					} catch (ClassCastException e) {
						continue;
						// TODO: handle exception
						//String[]로 캐스팅 되지 않는 것은 이쪽으로.
					}
				}
				//가장 긴 배열과 같은 길이의 항목만 목록데이터로 추가
                for (int i = 0; i < maxSize; i++) {
                    Hashtable<String, String> data = new Hashtable<String, String>();
                    for (Object key : keys) {
                        try {
                            data.put((String)key, ((String[])bindData.get(key))[i] != null ? ((String[])bindData.get(key))[i] : "");
                        } catch (Exception e) {
                            // TODO: handle exception
                            continue;
                        }
                    }
                    hashData.add(data);
                }
			}
			return hashData;		
		}
	}
}
